/*
 * @author: Duo Ji
 */
package com.server;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Date;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

import com.data.Request;
import com.data.SourceType;
import com.server.cm.NotificationManager;
import com.server.cm.RequestHandler;
import com.server.cm.Scheduler;
import com.util.Debug;

// TODO: Auto-generated Javadoc
/**
 * The Class Server. This is the driver class.
 */
public class Server {

	/**
	 * The main method.
	 * 
	 * @param args
	 *            the arguments
	 */
	public static void main(String[] args) {
		Debug.println("start server.main()");
		System.out.println("##################################################");
		System.out.println("### type command 'exit' to stop server program ###");
		System.out.println("##################################################");
		// creating request queue
		ConcurrentLinkedQueue<Request> reqQ = new ConcurrentLinkedQueue<Request>();
		AtomicLong reqIdCounter = new AtomicLong(0);
		ScheduledExecutorService exe = Executors.newScheduledThreadPool(10);

		// create and start schedulers
		Scheduler s10 = new Scheduler(reqQ, 10, reqIdCounter);
		Scheduler s20 = new Scheduler(reqQ, 10, reqIdCounter);
		Scheduler s30 = new Scheduler(reqQ, 30, reqIdCounter);
		Scheduler s60 = new Scheduler(reqQ, 60, reqIdCounter);
		exe.scheduleAtFixedRate(s10, 10, 10, TimeUnit.MINUTES);
		exe.scheduleAtFixedRate(s20, 20, 20, TimeUnit.MINUTES);
		exe.scheduleAtFixedRate(s30, 30, 30, TimeUnit.MINUTES);
		exe.scheduleAtFixedRate(s60, 40, 40, TimeUnit.MINUTES);

		// starting notification manager
		NotificationManager nm = new NotificationManager(reqQ);
		Thread nmThread = new Thread(nm);
		nmThread.start();
		RequestHandler rh = null;
		Thread rhThread;
		try {
			rh = new RequestHandler(10, 7890, reqIdCounter);
		} catch (IOException e1) {
			e1.printStackTrace();
			System.exit(1);
		}
		rhThread = new Thread(rh);
		rhThread.start();

		// see if there is 'exit' command
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		for (;;) {
			try {
				String input = in.readLine();
				if ("exit".equals(input)) {
					Debug.println("stopping server");
					break;
				}
			} catch (IOException e) {
				e.printStackTrace();
				break;
			}
		}

		// stop everything
		Request rt = new Request(0, null, null, SourceType.server, new Date());
		reqQ.add(rt);
		synchronized (reqQ) {
			reqQ.notify();
		}
		try {
			// waiting for Notification Manager
			nmThread.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		rhThread.interrupt();
		exe.shutdownNow();
		System.exit(0);
	}
}
